package com.xiaoshuidi.cloud.module.contract.service.bill;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xiaoshuidi.cloud.framework.common.exception.ServiceException;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.xiaoshuidi.cloud.framework.common.util.json.JsonUtils;
import com.xiaoshuidi.cloud.framework.mybatis.core.util.MyBatisUtils;
import com.xiaoshuidi.cloud.framework.redis.lock.DistributeLock;
import com.xiaoshuidi.cloud.framework.redis.sequence.TimebaseSequenceGenerator;
import com.xiaoshuidi.cloud.framework.security.core.LoginUser;
import com.xiaoshuidi.cloud.framework.security.core.util.SecurityFrameworkUtils;
import com.xiaoshuidi.cloud.framework.web.core.util.WebFrameworkUtils;
import com.xiaoshuidi.cloud.module.bpm.api.task.BpmProcessInstanceApi;
import com.xiaoshuidi.cloud.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import com.xiaoshuidi.cloud.module.bpm.enums.BpmBusinessTypeEnum;
import com.xiaoshuidi.cloud.module.bpm.enums.DictTypeConstants;
import com.xiaoshuidi.cloud.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import com.xiaoshuidi.cloud.module.bpm.mq.message.BpmProcessInstanceResultEvent;
import com.xiaoshuidi.cloud.module.contract.controller.admin.bill.DateRangeGenerator;
import com.xiaoshuidi.cloud.module.contract.controller.admin.bill.vo.OrderDetailVo;
import com.xiaoshuidi.cloud.module.contract.controller.admin.bill.vo.OrderResp;
import com.xiaoshuidi.cloud.module.contract.controller.admin.bill.vo.orderFees.OrderFeesCreateReqVO;
import com.xiaoshuidi.cloud.module.contract.controller.admin.bill.vo.ownerOrder.*;
import com.xiaoshuidi.cloud.module.contract.controller.admin.contract.vo.HomeQueryVO;
import com.xiaoshuidi.cloud.module.contract.controller.admin.contract.vo.ownerContract.ContractHouseOwnerCancelReqVO;
import com.xiaoshuidi.cloud.module.contract.controller.admin.contract.vo.ownerContract.ContractHouseOwnerRespVO;
import com.xiaoshuidi.cloud.module.contract.controller.admin.contract.vo.ownerContract.ContractOwnerEvictionFeeVO;
import com.xiaoshuidi.cloud.module.contract.controller.admin.contract.vo.ownerContract.ContractOwnerRoomRefVO;
import com.xiaoshuidi.cloud.module.contract.convert.bill.RentOrderConvert;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.bill.OrderFeesDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.bill.OwnerOrderTransferDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.bill.RentOrderDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.contract.ContractHouseOwnerDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.contract.ContractHouseOwnerRoomRefDO;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.bill.OrderFeesMapper;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.bill.RentOrderMapper;
import com.xiaoshuidi.cloud.module.contract.enums.ApiConstants;
import com.xiaoshuidi.cloud.module.contract.enums.ApproveTypeEnum;
import com.xiaoshuidi.cloud.module.contract.enums.bill.*;
import com.xiaoshuidi.cloud.module.contract.enums.contract.ContractNodeEnum;
import com.xiaoshuidi.cloud.module.contract.enums.contract.ContractOwnerEvictionHandleTypeEnum;
import com.xiaoshuidi.cloud.module.contract.enums.contract.ContractOwnerStatusEnum;
import com.xiaoshuidi.cloud.module.contract.service.approval.ContractApprovalService;
import com.xiaoshuidi.cloud.module.contract.service.bill.dto.RentOrderCreateDTO;
import com.xiaoshuidi.cloud.module.contract.service.bill.dto.RentOrderQueryDTO;
import com.xiaoshuidi.cloud.module.contract.service.contract.ContractHouseOwnerService;
import com.xiaoshuidi.cloud.module.contract.service.contract.dto.OwnerContractRentOrderDTO;
import com.xiaoshuidi.cloud.module.contract.util.bill.BillPeriod;
import com.xiaoshuidi.cloud.module.contract.util.bill.DayRent;
import com.xiaoshuidi.cloud.module.contract.vo.OwnerOrderTransferCallbackReqVO;
import com.xiaoshuidi.cloud.module.finance.api.finance.FinanceApi;
import com.xiaoshuidi.cloud.module.finance.api.finance.dto.BankTransferReqDTO;
import com.xiaoshuidi.cloud.module.finance.enums.ErrorCodeConstants;
import com.xiaoshuidi.cloud.module.finance.enums.finance.FinanceCustomerTypeEnum;
import com.xiaoshuidi.cloud.module.finance.enums.finance.SourceBizTypeEnum;
import com.xiaoshuidi.cloud.module.finance.enums.order.FinanceCommonStatusEnum;
import com.xiaoshuidi.cloud.module.system.api.user.AdminUserApi;
import com.xiaoshuidi.cloud.module.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static com.xiaoshuidi.cloud.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.xiaoshuidi.cloud.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
import static com.xiaoshuidi.cloud.module.contract.enums.ApiConstants.*;
import static com.xiaoshuidi.cloud.module.contract.enums.ErrorCodeConstants.*;

/**
 * @Description:
 * @author: zhaoyu
 * @date: 2023/6/14
 */
@Slf4j
@Service
public class OwnerOrderServiceImpl implements OwnerOrderService{
    @Resource
    private RentOrderMapper rentOrderMapper;
    @Resource
    private OrderFeesService orderFeesService;
    @Resource
    private TimebaseSequenceGenerator timebaseSequenceGenerator;
    @Resource
    private OrderFeesMapper orderFeesMapper;
    @Resource
    private ContractHouseOwnerService contractHouseOwnerService;
    @Resource
    private FinanceApi financeApi;

    @Resource
    private ContractApprovalService contractApprovalService;

    @Value("${spring.application.name}")
    private String applicationName;

    @Resource
    private BpmProcessInstanceApi bpmProcessInstanceApi;

    @Resource
    private AdminUserApi adminUserApi;


    @Override
    public PageResult<OwnerOrderRespVO> getOwnerOrderPage(OwnerOrderPageReqVO pageReqVO) {
        Page<OwnerOrderRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        pageReqVO.setOwnerOrderTypeList(Arrays.asList(OrderTypeEnum.OWNER.getCode(),
                OrderTypeEnum.OWNER_EVICTION.getCode()));
        pageReqVO.setUnprocessedStatusList(Arrays.asList(OrderPayStatusEnum.UNPAID.getCode(),
                OrderPayStatusEnum.PART.getCode()));
        pageReqVO.setProcessedStatus(OrderPayStatusEnum.PAID.getCode());
        pageReqVO.setNowDate(LocalDate.now());
        IPage<OwnerOrderRespVO> ownerOrderPage = rentOrderMapper.getOwnerOrderList(page, pageReqVO);
        List<OwnerOrderRespVO> ownerOrderList = null;
        if (Objects.nonNull(ownerOrderPage)){
            ownerOrderList = ownerOrderPage.getRecords();
            // 处理账单状态
            buildOwnerOrderList(ownerOrderList, pageReqVO.getUnprocessedStatusList());
            return new PageResult<>(ownerOrderList,  ownerOrderPage.getTotal());
        }
        return null;
    }

    private void buildOwnerOrderList(List<OwnerOrderRespVO> ownerOrderList,List<String> unprocessedStatusList){
        // 处理账单状态
        for (OwnerOrderRespVO record : ownerOrderList) {
            if (record.getApprovedStatus().equals(OrderApprovedStatusEnum.IN_REVIEW.getCode())){
                // 审批状态  待审批
                record.setOrderStatus(OwnerOrderStatusEnum.PENDING_APPROVAL.getCode());
            } else if (record.getApprovedStatus().equals(OrderApprovedStatusEnum.REJECT.getCode())) {
                // 审批状态  待审批
                record.setOrderStatus(OwnerOrderStatusEnum.REJECTED.getCode());
            }else if (record.getPayStatus().equals(OrderPayStatusEnum.PAID.getCode())){
                // 支付状态为已支付 已完成
                record.setOrderStatus(OwnerOrderStatusEnum.PROCESSED.getCode());
            }else if (unprocessedStatusList.contains(record.getPayStatus())){
                if (record.getOughtPayTime().isBefore(LocalDate.now())){
                    // 支付状态待支付、部分支付 & 支付时间在当前时间之前  已逾期
                    record.setOrderStatus(OwnerOrderStatusEnum.OVERDUE.getCode());
                }else {
                    // 支付状态待支付、部分支付 & 支付时间在当前时间之后  待处理
                    record.setOrderStatus(OwnerOrderStatusEnum.PENDING_PROCESSING.getCode());
                }
            }else if (record.getPayStatus().equals(OrderPayStatusEnum.CANCEL.getCode())){
                record.setOrderStatus(OwnerOrderStatusEnum.CANCELED.getCode());
            }
            // 应付款金额
            BigDecimal subtract = BigDecimal.ZERO;
            if (OrderPayStatusEnum.PAID.getCode().equals(record.getPayStatus())){
                subtract = record.getActualPaymentAmount();
            }else {
                subtract = record.getTotalAmount().subtract(record.getPaidRentUtilities());
            }
            record.setAmount(subtract.compareTo(BigDecimal.ZERO)>=0?subtract:BigDecimal.ZERO);
        }
    }

    @Override
    public List<OwnerOrderRespVO> getOwnerOrderList(OwnerOrderPageReqVO pageReqVO) {
        pageReqVO.setOwnerOrderTypeList(Arrays.asList(OrderTypeEnum.OWNER.getCode(),OrderTypeEnum.OWNER_EVICTION.getCode()));
        pageReqVO.setUnprocessedStatusList(Arrays.asList(OrderPayStatusEnum.UNPAID.getCode(),OrderPayStatusEnum.PART.getCode()));
        pageReqVO.setProcessedStatus(OrderPayStatusEnum.PAID.getCode());
        pageReqVO.setNowDate(LocalDate.now());
        List<OwnerOrderRespVO> ownerOrderList = rentOrderMapper.getOwnerOrderList(pageReqVO);
        buildOwnerOrderList(ownerOrderList,pageReqVO.getUnprocessedStatusList());
        return ownerOrderList;
    }

    @Override
    public void ownerContractCreateRentOrder(OwnerContractRentOrderDTO ownerContractRentOrderDTO) {
//        if (Objects.nonNull(ownerContractRentOrderDTO.getOriginalContractId())){
//            // 续租业主合同  押金默认0  后续会处理
//            ownerContractRentOrderDTO.setDepositAmount(BigDecimal.ZERO);
//        }
        // 根据账单计算账单金额
        OrderResp orderResp = DateRangeGenerator.calculateOwnerBillAmount(ownerContractRentOrderDTO);
        List<OrderDetailVo> orderDetailList = orderResp.getOrderDetailVos();

        // 构建实体
        List<RentOrderCreateDTO> rentOrderCreateList = new ArrayList<>();
        for (OrderDetailVo orderDetail : orderDetailList) {
            RentOrderCreateDTO rentOrderCreate = RentOrderConvert.INSTANCE.convertOrderDetail2RentOrderCreate(orderDetail);
            rentOrderCreate.setOughtPayTime(orderDetail.getReceivablesTime());
            rentOrderCreate.setDeadlinePayTime(orderDetail.getReceivablesTime());
            rentOrderCreate.setBusinessId(ownerContractRentOrderDTO.getBusinessId());
            rentOrderCreate.setApartmentId(ownerContractRentOrderDTO.getApartmentId());
            rentOrderCreate.setApartmentName(ownerContractRentOrderDTO.getApartmentName());
            rentOrderCreate.setRoomId(ownerContractRentOrderDTO.getRoomId());
            rentOrderCreate.setRoomName(ownerContractRentOrderDTO.getRoomName());
            rentOrderCreate.setApprovedStatus(OrderApprovedStatusEnum.NO_AUDIT_REQUITED.getCode());
            rentOrderCreate.setOrderType(ownerContractRentOrderDTO.getOrderType());
            rentOrderCreate.setRawAmount(BigDecimal.ZERO);
            rentOrderCreate.setPayOutStatus(ZERO);
            rentOrderCreate.setDiscountAmount(orderDetail.getDiscountValue().add(orderDetail.getExtraDiscountValue()));
            rentOrderCreate.setFlowType(OrderFeeFlowTypeEnum.OUTFLOW.getCode());
            rentOrderCreateList.add(rentOrderCreate);
        }
        // 创建账单及明细
        createRentOrderAndOrderFees(rentOrderCreateList, YZHTZD, ownerContractRentOrderDTO.getCarryForwardDeposit());
    }

    @Override
    public void createRentOrderAndOrderFees(List<RentOrderCreateDTO> rentOrderCreateList, String typeCode, BigDecimal carryForwardDeposit) {
        List<RentOrderDO> rentOrderList = new ArrayList<>();
        int num = 1;
        rentOrderCreateList = Optional.ofNullable(rentOrderCreateList).orElse(new ArrayList<>());

        // 校验结转押金
        if (Objects.nonNull(carryForwardDeposit)){
            BigDecimal reduce = rentOrderCreateList.stream().map(RentOrderCreateDTO::getTotalAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            if (carryForwardDeposit.compareTo(reduce) > 0){
                // 结转押金比所有账单总额还大  抛出异常
                throw exception(CONTRACT_OWNER_RENEWAL_DEPOSIT_CARRY_FORWARD_ERROR);
            }
        }
        // 排序
        Collections.sort(rentOrderCreateList, Comparator.comparing(RentOrderCreateDTO::getStartTime));
        //构建账单对象
        for (RentOrderCreateDTO item : rentOrderCreateList) {
            RentOrderDO rentOrder = RentOrderConvert.INSTANCE.convert(item);
            rentOrder.setUuid(UUID.randomUUID().toString(true));
            rentOrder.setOrderNo(typeCode + timebaseSequenceGenerator.YYYYMMDD.next(ApiConstants.BILL, "%06d"));
            rentOrder.setNum(num++);
            rentOrder.setTotalNum(rentOrderCreateList.size());
            rentOrder.setDeptId(item.getApartmentId());
            // 顺序抵扣
            if (Objects.nonNull(carryForwardDeposit) && carryForwardDeposit.compareTo(BigDecimal.ZERO) > 0){
                if (carryForwardDeposit.compareTo(rentOrder.getTotalAmount()) >= 0){
                    // 结转押金完全抵扣账单
                    rentOrder.setPaidRentUtilities(rentOrder.getTotalAmount());
                    rentOrder.setPayStatus(OrderPayStatusEnum.PAID.getCode());
                    List<OrderFeesCreateReqVO> feeDetail = rentOrder.getFeeDetail();
                    // 账单明细全部支付
                    feeDetail.forEach(fee -> {
                        fee.setPaidAmount(fee.getAmount());
                        fee.setPayStatus(OrderPayStatusEnum.PAID.getCode());
                    });
                    // 剩余结转押金
                    carryForwardDeposit = carryForwardDeposit.subtract(rentOrder.getTotalAmount());
                }else {
                    // 结转押金只够抵扣部分  优先抵扣押金
                    if (Objects.nonNull(rentOrder.getDepositAmount()) && rentOrder.getDepositAmount().compareTo(BigDecimal.ZERO) > 0){
                        // 押金完全抵扣
                        if (carryForwardDeposit.compareTo(rentOrder.getDepositAmount()) >= 0) {
                            rentOrder.setPaidRentUtilities(rentOrder.getDepositAmount());
                            rentOrder.setPayStatus(OrderPayStatusEnum.PART.getCode());
                            carryForwardDeposit = carryForwardDeposit.subtract(rentOrder.getDepositAmount());
                            // 抵扣完押金还有剩余 抵扣租金
                            if (carryForwardDeposit.compareTo(BigDecimal.ZERO) > 0){
                                // 此处肯定只够抵扣一部分租金
                                rentOrder.setPaidRentUtilities(rentOrder.getDepositAmount().add(carryForwardDeposit));
                            }
                            List<OrderFeesCreateReqVO> feeDetail = rentOrder.getFeeDetail();
                            // 账单明细部分支付
                            BigDecimal finalCarryForwardDeposit = carryForwardDeposit;
                            feeDetail.forEach(fee -> {
                                if (DEPOSIT_FEE_ID == fee.getFeeId()){
                                    // 押金
                                    fee.setPaidAmount(fee.getAmount());
                                    fee.setPayStatus(OrderPayStatusEnum.PAID.getCode());
                                }else if (RENT_FEE_ID == fee.getFeeId()){
                                    // 租金
                                    fee.setPaidAmount(finalCarryForwardDeposit);
                                    fee.setPayStatus(OrderPayStatusEnum.PART.getCode());
                                }
                            });
                        }else {
                            // 押金部分抵扣
                            rentOrder.setPaidRentUtilities(carryForwardDeposit);
                            rentOrder.setPayStatus(OrderPayStatusEnum.PART.getCode());
                            List<OrderFeesCreateReqVO> feeDetail = rentOrder.getFeeDetail();
                            // 账单明细部分支付
                            BigDecimal finalCarryForwardDeposit = carryForwardDeposit;
                            feeDetail.forEach(fee -> {
                                if (DEPOSIT_FEE_ID == fee.getFeeId()){
                                    // 押金
                                    fee.setPaidAmount(finalCarryForwardDeposit);
                                    fee.setPayStatus(OrderPayStatusEnum.PART.getCode());
                                }
                            });
                        }
                    }else {
                        // 无押金  抵扣租金
                        rentOrder.setPaidRentUtilities(carryForwardDeposit);
                        rentOrder.setPayStatus(OrderPayStatusEnum.PART.getCode());
                        List<OrderFeesCreateReqVO> feeDetail = rentOrder.getFeeDetail();
                        // 账单明细部分支付
                        BigDecimal finalCarryForwardDeposit = carryForwardDeposit;
                        feeDetail.forEach(fee -> {
                            if (RENT_FEE_ID == fee.getFeeId()){
                                // 租金
                                fee.setPaidAmount(finalCarryForwardDeposit);
                                fee.setPayStatus(OrderPayStatusEnum.PART.getCode());
                            }
                        });
                    }
                    // 结转金额已经抵扣完
                    carryForwardDeposit = BigDecimal.ZERO;
                }
            }
            rentOrderList.add(rentOrder);
        }
        rentOrderMapper.insertBatch(rentOrderList);

        // 创建账单明细
        orderFeesService.createBatchOrderFees(rentOrderList);
    }

    /**
     * 业主合同退租已付应退账单详情
     */
    private List<OrderFeesDO> getRefundOrderFeesList(Long businessId, LocalDate untilTime,BigDecimal monthRent) {
        // 查询退租日期后的所有已付款完成的账单  已付应退
        List<OrderFeesDO> feeDetailList = new ArrayList<>();
        LambdaQueryWrapper<RentOrderDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RentOrderDO::getBusinessId, businessId);
        queryWrapper.eq(RentOrderDO::getOrderType, OrderTypeEnum.OWNER.getCode());
        queryWrapper.gt(Objects.nonNull(untilTime), RentOrderDO::getEndTime, untilTime.atStartOfDay());
        queryWrapper.in(RentOrderDO::getPayStatus, Arrays.asList(OrderPayStatusEnum.PAID.getCode(), OrderPayStatusEnum.PART.getCode()));
        queryWrapper.orderByAsc(RentOrderDO::getNum);
        List<RentOrderDO> rentOrderList = rentOrderMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(rentOrderList)){
            return null;
        }
        // 已付应退第一期账单
        RentOrderDO firstRentOrder = rentOrderList.get(ZERO);
        if (!firstRentOrder.getStartTime().equals(untilTime)){
            // 本期部分需要退款
            // 计算日租金
            BigDecimal dayRent = DayRent.calculateDailyAmount(firstRentOrder.getStartTime(), monthRent);
            Period until = untilTime.until(firstRentOrder.getEndTime());
            // 业主应退金额
            BigDecimal amount = dayRent.multiply(new BigDecimal(until.getDays() + 1));
            OrderFeesDO feesDetail = new OrderFeesDO();
            feesDetail.setAmount(amount);
            feesDetail.setFlowType(OrderFeeFlowTypeEnum.INFLOW.getCode());
            feesDetail.setFeeId(ApiConstants.RENT_FEE_ID);
            feesDetail.setFeeName(ApiConstants.RENT_FEE_NAME);
            feesDetail.setStartTime(firstRentOrder.getStartTime());
            feesDetail.setEndTime(firstRentOrder.getEndTime());
            feeDetailList.add(feesDetail);
            rentOrderList.remove(firstRentOrder);
        }
        for (RentOrderDO rentOrderDO : rentOrderList) {
            List<OrderFeesDO> orderFeesByOrderId = orderFeesService.getOrderFeesByOrderId(rentOrderDO.getId());
            if (CollectionUtils.isNotEmpty(orderFeesByOrderId)) {
                orderFeesByOrderId.forEach(f ->{
                    f.setFlowType(OrderFeeFlowTypeEnum.INFLOW.getCode());
                    f.setActualPayTime(null);
                    f.setPayStatus(OrderPayStatusEnum.UNPAID.getCode());
                    f.setPaidAmount(null);
                });
                feeDetailList.addAll(orderFeesByOrderId);
                // 首期账单中的押金账单已处理 不需要再次处理
                if (rentOrderDO.getNum() == ONE.intValue()){
                    OrderFeesDO depositFeesDO = orderFeesByOrderId.stream()
                            .filter(f -> ApiConstants.DEPOSIT_FEE_ID.intValue() == f.getFeeId()
                                    && ApiConstants.DEPOSIT_FEE_NAME.equals(f.getFeeName())).findFirst().orElse(null);
                    if (Objects.nonNull(depositFeesDO)){
                        feeDetailList.remove(depositFeesDO);
                    }
                }
            }
        }
        return feeDetailList;
    }

    /**
     * 应付但未付的账单明细
     */
    private List<OrderFeesDO> getOwnerUnpaidOrderFeesList(ContractHouseOwnerCancelReqVO reqVo) {
        LocalDate untilTime = reqVo.getEvictionTime();
        // 查询退租日期前的所有未付款完成的账单  应付但未付的账单
        List<OrderFeesDO> feeDetailList = new ArrayList<>();
        LambdaQueryWrapper<RentOrderDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RentOrderDO::getBusinessId, reqVo.getOwnerContractId());
        queryWrapper.eq(RentOrderDO::getOrderType, OrderTypeEnum.OWNER.getCode());
        queryWrapper.le(Objects.nonNull(untilTime), RentOrderDO::getStartTime, untilTime.atStartOfDay());
        queryWrapper.in(RentOrderDO::getPayStatus, Arrays.asList(OrderPayStatusEnum.UNPAID.getCode(), OrderPayStatusEnum.PART.getCode()));
        queryWrapper.orderByAsc(RentOrderDO::getNum);
        List<RentOrderDO> rentOrderList = rentOrderMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(rentOrderList)){
            return null;
        }
        // 最后一期账单
        RentOrderDO lastRentOrder = rentOrderList.get(rentOrderList.size() - ONE);
        if (reqVo.getEndTime().isBefore(lastRentOrder.getEndTime()) && lastRentOrder.getEndTime().isBefore(untilTime)){
            // 退租时间晚于租期 需要计算额外的租金费用
            List<BillPeriod> billPeriods = BillPeriod.splitByMonth(lastRentOrder.getEndTime(), untilTime, ONE);
            if (CollectionUtils.isNotEmpty(billPeriods)){
                BigDecimal amount = BigDecimal.ZERO;
                for (BillPeriod billPeriod : billPeriods) {
                    BillPeriod.MonthAndRemainder monthAndRemainder = billPeriod.monthAndRemainder();
                    //计算日租金
                    BigDecimal dayRent = DayRent.calculateDailyAmount(billPeriod.getStartTime(), reqVo.getMonthRent());
                    if (monthAndRemainder.getRemainder() > 0 && billPeriod.getEndTime().isEqual(untilTime)) {
                        amount = amount.add(dayRent.multiply(BigDecimal.valueOf(monthAndRemainder.getRemainder())));
                    }else {
                        amount = amount.add(lastRentOrder.getRentAmount());
                    }
                }
                OrderFeesDO feesDetail = new OrderFeesDO();
                feesDetail.setAmount(amount);
                feesDetail.setFeeId(ApiConstants.RENT_FEE_ID);
                feesDetail.setFeeName(ApiConstants.RENT_FEE_NAME);
                feesDetail.setStartTime(lastRentOrder.getStartTime());
                feesDetail.setEndTime(lastRentOrder.getEndTime());
                feeDetailList.add(feesDetail);
            }

        }else if (untilTime.isBefore(reqVo.getEndTime()) && (lastRentOrder.getStartTime().isBefore(untilTime) || lastRentOrder.getStartTime().equals(untilTime))){
            // 退租时间早于租期结束时间  需要拆分账单
            // 计算日租金
            BigDecimal dayRent = DayRent.calculateDailyAmount(lastRentOrder.getStartTime(), reqVo.getMonthRent());
            Period until = lastRentOrder.getStartTime().until(untilTime);
            BigDecimal amount = dayRent.multiply(new BigDecimal(until.getDays()+ONE));
            OrderFeesDO feesDetail = new OrderFeesDO();
            feesDetail.setAmount(amount);
            feesDetail.setFeeId(ApiConstants.RENT_FEE_ID);
            feesDetail.setFeeName(ApiConstants.RENT_FEE_NAME);
            feesDetail.setStartTime(lastRentOrder.getStartTime());
            feesDetail.setEndTime(lastRentOrder.getEndTime());
            feeDetailList.add(feesDetail);
            rentOrderList.remove(lastRentOrder);
        }

        for (RentOrderDO rentOrderDO : rentOrderList) {
            List<OrderFeesDO> orderFeesByOrderId = orderFeesService.getOrderFeesByOrderId(rentOrderDO.getId());
            if (CollectionUtils.isNotEmpty(orderFeesByOrderId)) {
                feeDetailList.addAll(orderFeesByOrderId);
                // 首期账单中的押金账单已处理 不需要再次处理
                if (rentOrderDO.getNum() == ONE.intValue()){
                    OrderFeesDO depositFeesDO = orderFeesByOrderId.stream()
                            .filter(f -> ApiConstants.DEPOSIT_FEE_ID.intValue() == f.getFeeId()
                                    && ApiConstants.DEPOSIT_FEE_NAME.equals(f.getFeeName())).findFirst().orElse(null);
                    if (Objects.nonNull(depositFeesDO)){
                        feeDetailList.remove(depositFeesDO);
                    }
                }
            }
        }
        return feeDetailList;
    }

    @Override
    @Transactional
    public RentOrderCreateDTO ownerWithdrawal(ContractHouseOwnerCancelReqVO reqVo,
                                              ContractHouseOwnerRoomRefDO ownerRoomRef) {
        // 查询未付款账单明细 未付应付
        List<OrderFeesDO> unpaidOrderFeesList = getOwnerUnpaidOrderFeesList(reqVo);
        // 查询已付需要退的账单明细 已付应退
        List<OrderFeesDO> refundOrderFeesList = getRefundOrderFeesList(reqVo.getOwnerContractId(),
                reqVo.getEvictionTime(), reqVo.getMonthRent());

        List<OrderFeesCreateReqVO> feeDetails = new ArrayList<>();
        //租金账单 明细
        OrderFeesCreateReqVO rentDetail = rentHandle(reqVo.getRentHandleAmount(), reqVo.getRentHandleType(),
                reqVo.getEvictionTime());
        feeDetails.add(rentDetail);

        //押金账单 明细
        OrderFeesCreateReqVO despositDetail = depositHandle(reqVo.getDepositHandleAmount(), reqVo.getEvictionTime());
        feeDetails.add(despositDetail);

        // 未付款账单 以及 其他杂费处理
        List<OrderFeesCreateReqVO> feesDetailList = evictionFeeCalculation(unpaidOrderFeesList,refundOrderFeesList, reqVo.getFeeList(), reqVo.getEvictionTime());
//        List<OrderFeesCreateReqVO> feesDetailList = evictionFeeCalculation(null,null, reqVo.getFeeList(), reqVo.getEvictionTime());
        if (CollectionUtils.isNotEmpty(feesDetailList)){
            feeDetails.addAll(feesDetailList);
        }

        //计算账单总金额
        BigDecimal amount = BigDecimal.ZERO;
        for (OrderFeesCreateReqVO feeDetail : feeDetails) {
            if (feeDetail.getFlowType().intValue() == OrderFeeFlowTypeEnum.INFLOW.getCode().intValue()){
                amount = amount.add(feeDetail.getAmount());
            }else if (feeDetail.getFlowType().intValue() == OrderFeeFlowTypeEnum.OUTFLOW.getCode().intValue()){
                amount = amount.subtract(feeDetail.getAmount());
            }
        }

        // 构建账单新增对象
        RentOrderCreateDTO rentOrderCreate = new RentOrderCreateDTO();
        if (amount.compareTo(BigDecimal.ZERO) < 0){
            rentOrderCreate.setTotalAmount(amount.abs());
            rentOrderCreate.setFlowType(OrderFeeFlowTypeEnum.OUTFLOW.getCode());
        }else {
            rentOrderCreate.setTotalAmount(amount);
            rentOrderCreate.setFlowType(OrderFeeFlowTypeEnum.INFLOW.getCode());
        }
        rentOrderCreate.setBusinessId(reqVo.getOwnerContractId());
        rentOrderCreate.setApartmentId(ownerRoomRef.getApartmentId());
        rentOrderCreate.setApartmentName(ownerRoomRef.getApartmentName());
        rentOrderCreate.setRoomId(ownerRoomRef.getRoomId());
        rentOrderCreate.setRoomName(ownerRoomRef.getRoomName());
        rentOrderCreate.setOughtPayTime(reqVo.getEvictionTime());
        rentOrderCreate.setDeadlinePayTime(reqVo.getEvictionTime());

        rentOrderCreate.setOrderType(OrderTypeEnum.OWNER_EVICTION.getCode());
        rentOrderCreate.setFeeDetail(feeDetails);
        rentOrderCreate.setStartTime(reqVo.getEvictionTime());
        rentOrderCreate.setEndTime(reqVo.getEvictionTime());
        rentOrderCreate.setOughtPayTime(reqVo.getEvictionTime());
        rentOrderCreate.setDeadlinePayTime(reqVo.getEvictionTime());

        rentOrderCreate.setApprovedStatus(OrderApprovedStatusEnum.NO_AUDIT_REQUITED.getCode());
        // 业主退租账单审批待定
        if (reqVo.getIsBpmApprove() == null || !reqVo.getIsBpmApprove()) {
            List<RentOrderCreateDTO> rentOrderCreateList = new ArrayList<>();
            rentOrderCreateList.add(rentOrderCreate);
            createRentOrderAndOrderFees(rentOrderCreateList, YZHTZD, null);
            // 未付款账单状态改为取消
            cancelUnpaidOrder(reqVo);
            return null;
        } else {
            return rentOrderCreate;
        }

    }

    /**
     * 取消未付款账单
     */
    public void cancelUnpaidOrder(ContractHouseOwnerCancelReqVO reqVo) {
//        List<RentOrderDO> unpaidOrderList = getOwnerUnpaidOrder(reqVo.getOwnerContractId(), reqVo.getEvictionTime());
        LambdaQueryWrapper<RentOrderDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RentOrderDO::getBusinessId, reqVo.getOwnerContractId());
        queryWrapper.eq(RentOrderDO::getOrderType, OrderTypeEnum.OWNER.getCode());
        queryWrapper.in(RentOrderDO::getPayStatus, Arrays.asList(OrderPayStatusEnum.UNPAID.getCode(),
                OrderPayStatusEnum.PART.getCode()));
        List<RentOrderDO> unpaidOrderList = rentOrderMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(unpaidOrderList)) {
            return;
        }
        List<Long> ids = unpaidOrderList.stream().map(RentOrderDO::getId).collect(Collectors.toList());
        LambdaUpdateWrapper<RentOrderDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(RentOrderDO::getId, ids);
        updateWrapper.set(RentOrderDO::getPayStatus, OrderPayStatusEnum.CANCEL.getCode());
        rentOrderMapper.update(null, updateWrapper);
        LambdaUpdateWrapper<OrderFeesDO> feesUpdateWrapper = new LambdaUpdateWrapper<>();
        feesUpdateWrapper.in(OrderFeesDO::getOrderId, ids);
        feesUpdateWrapper.set(OrderFeesDO::getPayStatus, OrderPayStatusEnum.CANCEL.getCode());
        orderFeesMapper.update(null, feesUpdateWrapper);
    }

    /**
     * 租金账单处理
     */
    private OrderFeesCreateReqVO rentHandle(BigDecimal rentHandleAmount, Integer rentHandleType, LocalDate endTime){
        //租金账单 明细
        OrderFeesCreateReqVO rentDetail = new OrderFeesCreateReqVO();
        rentDetail.setOrderType(OrderTypeEnum.OWNER_EVICTION.getCode());
        rentDetail.setFeeId(ApiConstants.RENT_FEE_ID);
        rentDetail.setFeeName(ApiConstants.RENT_FEE_NAME);
        rentDetail.setAmount(rentHandleAmount);
        rentDetail.setStartTime(LocalDate.now());
        rentDetail.setEndTime(endTime);
        if (rentHandleType.intValue() == ContractOwnerEvictionHandleTypeEnum.RECEIVABLE.getCode().intValue()){
            rentDetail.setFlowType(OrderFeeFlowTypeEnum.OUTFLOW.getCode());
        }else if (rentHandleType.intValue() == ContractOwnerEvictionHandleTypeEnum.REFUNDABLE.getCode().intValue()){
            rentDetail.setFlowType(OrderFeeFlowTypeEnum.INFLOW.getCode());
        }
        rentDetail.setFeeSort(OrderFeeSortTypeEnum.ONCE.getCode());
        return rentDetail;
    }

    /**
     * 押金账单处理
     */
    private OrderFeesCreateReqVO depositHandle(BigDecimal depositAmount, LocalDate endTime){
        //押金账单 明细
        OrderFeesCreateReqVO depositDetail = new OrderFeesCreateReqVO();
        depositDetail.setOrderType(OrderTypeEnum.OWNER_EVICTION.getCode());
        depositDetail.setFeeId(ApiConstants.DEPOSIT_FEE_ID);
        depositDetail.setFeeName(ApiConstants.DEPOSIT_FEE_NAME);
        depositDetail.setAmount(depositAmount);
        // 押金处理方式 全退、部分退、不退  直接默认流入
        depositDetail.setFlowType(OrderFeeFlowTypeEnum.INFLOW.getCode());
        depositDetail.setFeeSort(OrderFeeSortTypeEnum.ONCE.getCode());
        depositDetail.setStartTime(LocalDate.now());
        depositDetail.setEndTime(endTime);
        return depositDetail;
    }

    /**
     * 退租账单明细计算
     */
    private List<OrderFeesCreateReqVO> evictionFeeCalculation(List<OrderFeesDO> unpaidOrder,List<OrderFeesDO> refundOrderFeesList, List<ContractOwnerEvictionFeeVO> feeList, LocalDate endTime){
        List<OrderFeesCreateReqVO> list = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(unpaidOrder)){
            for (OrderFeesDO orderDetail : unpaidOrder) {
                OrderFeesCreateReqVO orderFees = new OrderFeesCreateReqVO();
                orderFees.setOrderType(OrderTypeEnum.OWNER_EVICTION.getCode());
                orderFees.setFeeId(orderDetail.getFeeId());
                orderFees.setFeeName(orderDetail.getFeeName());
                orderFees.setAmount(orderDetail.getAmount().subtract(Objects.nonNull(orderDetail.getDiscountAmount())?orderDetail.getDiscountAmount():BigDecimal.ZERO));
                orderFees.setFlowType(OrderFeeFlowTypeEnum.OUTFLOW.getCode());
                orderFees.setFeeSort(OrderFeeSortTypeEnum.ONCE.getCode());
                orderFees.setStartTime(orderDetail.getStartTime());
                orderFees.setStartTime(orderDetail.getEndTime());
                list.add(orderFees);
            }
        }
        if (CollectionUtils.isNotEmpty(refundOrderFeesList)){
            for (OrderFeesDO orderDetail : refundOrderFeesList) {
                OrderFeesCreateReqVO orderFees = new OrderFeesCreateReqVO();
                orderFees.setOrderType(OrderTypeEnum.OWNER_EVICTION.getCode());
                orderFees.setFeeId(orderDetail.getFeeId());
                orderFees.setFeeName(orderDetail.getFeeName());
                orderFees.setAmount(orderDetail.getAmount().subtract(Objects.nonNull(orderDetail.getDiscountAmount())?orderDetail.getDiscountAmount():BigDecimal.ZERO));
                orderFees.setFlowType(OrderFeeFlowTypeEnum.INFLOW.getCode());
                orderFees.setFeeSort(OrderFeeSortTypeEnum.ONCE.getCode());
                orderFees.setStartTime(orderDetail.getStartTime());
                orderFees.setStartTime(orderDetail.getEndTime());
                list.add(orderFees);
            }
        }

        if (CollectionUtils.isNotEmpty(feeList)){
            for (ContractOwnerEvictionFeeVO ownerEvictionFee : feeList) {
                OrderFeesCreateReqVO orderFees = new OrderFeesCreateReqVO();
                orderFees.setOrderType(OrderTypeEnum.OWNER_EVICTION.getCode());
                orderFees.setFeeId(ownerEvictionFee.getFeeId());
                orderFees.setFeeName(ownerEvictionFee.getFeeName());
                orderFees.setAmount(ownerEvictionFee.getFeeAmount());
                if (ownerEvictionFee.getOperationType().intValue() == ContractOwnerEvictionHandleTypeEnum.RECEIVABLE.getCode().intValue()){
                    orderFees.setFlowType(OrderFeeFlowTypeEnum.OUTFLOW.getCode());
                }else if (ownerEvictionFee.getOperationType().intValue() == ContractOwnerEvictionHandleTypeEnum.REFUNDABLE.getCode().intValue()){
                    orderFees.setFlowType(OrderFeeFlowTypeEnum.INFLOW.getCode());
                }
                orderFees.setFeeSort(OrderFeeSortTypeEnum.ONCE.getCode());
                orderFees.setStartTime(endTime);
                orderFees.setEndTime(endTime);
                list.add(orderFees);
            }
        }
        return list;
    }

    @Override
    public void deleteOrderByBusinessId(Long businessId, String orderType) {
        if (Objects.isNull(businessId) || StringUtils.isBlank(orderType)) {
            return;
        }
        LambdaQueryWrapper<RentOrderDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RentOrderDO::getBusinessId, businessId);
        queryWrapper.eq(RentOrderDO::getOrderType, orderType);
        List<RentOrderDO> rentOrderDOList = rentOrderMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(rentOrderDOList)) {
            List<Long> ids = rentOrderDOList.stream().map(RentOrderDO::getId).collect(Collectors.toList());
            LambdaQueryWrapper<OrderFeesDO> feeQueryWrapper = new LambdaQueryWrapper<>();
            feeQueryWrapper.in(OrderFeesDO::getOrderId, ids);
            orderFeesMapper.delete(feeQueryWrapper);
            rentOrderMapper.deleteBatchIds(ids);
        }
    }

    /**
     * 判断账单押金账单明细是否已支付
     */
    private Boolean checkOwnerOrderDepositPayStatus(RentOrderDO rentOrder) {
        if (OrderPayStatusEnum.PAID.getCode().equals(rentOrder.getPayStatus())){
            // 账单已支付完成
            return true;
        }
        if (OrderPayStatusEnum.PART.getCode().equals(rentOrder.getPayStatus())){
            // 账单部分支付 查询押金账单明细是否已支付
            List<OrderFeesDO> orderFeesList = getDepositOrderFees(rentOrder.getId());
            if (CollectionUtils.isNotEmpty(orderFeesList)){
                OrderFeesDO orderFeesDO = orderFeesList.get(ZERO);
                return OrderPayStatusEnum.PAID.getCode().equals(orderFeesDO.getPayStatus());
            }
        }
        return false;
    }

    /**
     * 业主合同编号查询首期账单
     */
    private RentOrderDO getOwnerFirstOrder(Long ownerContractId) {
        LambdaQueryWrapper<RentOrderDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RentOrderDO::getBusinessId, ownerContractId);
        queryWrapper.eq(RentOrderDO::getOrderType, OrderTypeEnum.OWNER.getCode());
        queryWrapper.eq(RentOrderDO::getNum, ONE);
        RentOrderDO rentOrder = rentOrderMapper.selectOne(queryWrapper);
        return rentOrder;
    }


    // 获取押金账单明细
    private List<OrderFeesDO> getDepositOrderFees(Long orderId){
        LambdaQueryWrapper<OrderFeesDO> feesQueryWrapper = new LambdaQueryWrapper<>();
        feesQueryWrapper.eq(OrderFeesDO::getOrderId, orderId);
        feesQueryWrapper.eq(OrderFeesDO::getFeeSort, OrderFeeSortTypeEnum.DEPOSIT.getCode());
        feesQueryWrapper.eq(OrderFeesDO::getFeeId, ApiConstants.DEPOSIT_FEE_ID);
        return orderFeesMapper.selectList(feesQueryWrapper);
    }

    @Override
    public OwnerOrderInfoRespVO getOwnerOrderInfo(Long orderId) {
        RentOrderDO rentOrderDO = rentOrderMapper.selectById(orderId);
        if (Objects.isNull(rentOrderDO)){
            throw exception(CONTRACT_RENTORDER_NOT_EXISTS);
        }
        OwnerOrderInfoRespVO orderInfoResp = RentOrderConvert.INSTANCE.convert2OwnerOrderInfo(rentOrderDO);
        List<String> orderTypeList = Arrays.asList(OrderTypeEnum.OWNER.getCode(), OrderTypeEnum.OWNER_EVICTION.getCode());
        if (orderTypeList.contains(rentOrderDO.getOrderType()) && Objects.nonNull(rentOrderDO.getBusinessId())){
            // 查询业主合同信息
            ContractHouseOwnerDO houseOwner = contractHouseOwnerService.getHouseOwner(rentOrderDO.getBusinessId());
            if (Objects.isNull(houseOwner)){
                throw exception(HOUSE_OWNER_NOT_EXISTS);
            }
            orderInfoResp.setOwnerName(houseOwner.getOwnerName());
            orderInfoResp.setCreditCard(houseOwner.getCreditCard());
            orderInfoResp.setBank(houseOwner.getBank());
            orderInfoResp.setBranchBank(houseOwner.getBranchBank());
            orderInfoResp.setCardholder(houseOwner.getCardholder());
            orderInfoResp.setOrderId(orderId);
            orderInfoResp.setBankProvince(houseOwner.getBankProvince());
            orderInfoResp.setBankCity(houseOwner.getBankCity());
            orderInfoResp.setBankCode(houseOwner.getBankCode());
            orderInfoResp.setPhone(houseOwner.getPhone());
        }
        return orderInfoResp;
    }


    @Override
    public Boolean checkOwnerOrderRentOut(Long orderId) {
        if (Objects.isNull(orderId)){
            return false;
        }

        RentOrderDO rentOrderDO = rentOrderMapper.selectById(orderId);
        //  账单是业主退租账单
        if (Objects.nonNull(rentOrderDO) && OrderTypeEnum.OWNER_EVICTION.getCode().equals(rentOrderDO.getOrderType())){
            return false;
        }
        if (Objects.nonNull(rentOrderDO) && OrderTypeEnum.OWNER.getCode().equals(rentOrderDO.getOrderType())){
            LambdaQueryWrapper<RentOrderDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(RentOrderDO::getBusinessId, rentOrderDO.getBusinessId());
            queryWrapper.eq(RentOrderDO::getOrderType, OrderTypeEnum.OWNER_EVICTION.getCode());
            List<RentOrderDO> rentOrderDOList = rentOrderMapper.selectList(queryWrapper);
            if (CollectionUtils.isNotEmpty(rentOrderDOList)){
                return true;
            }
        }
        return false;
    }

    @Override
    public void ownerOrderPaidHandleRenewalOrders(Long orderId) {
        RentOrderDO rentOrderDO = rentOrderMapper.selectById(orderId);
        if (Objects.isNull(rentOrderDO)){
            return;
        }
        // 首期账单
        if (ONE.intValue() == rentOrderDO.getNum()){
            // 处理续租合同的首期账单押金账单
            handleRenewalOwnerContractOrder(rentOrderDO.getBusinessId(), orderId);
        }
    }

    /**
     * 处理续租合同的首期账单押金账单
     */
    private void handleRenewalOwnerContractOrder(Long contractId, Long orderId){
        // 判断是否为根合同
        ContractHouseOwnerDO houseOwner = contractHouseOwnerService.getHouseOwner(contractId);
        // 根合同必为新签节点
        if (!ContractNodeEnum.NEW.getCode().equals(houseOwner.getContractNode()) || Objects.nonNull(houseOwner.getRootId())){
            return;
        }
        // 查询所有续租合同
        List<ContractHouseOwnerDO> renewalOwnerContractList = contractHouseOwnerService.getRenewalOwnerContractByContractId(contractId);
        if (CollectionUtils.isNotEmpty(renewalOwnerContractList)){
            for (ContractHouseOwnerDO renewalOwnerContract : renewalOwnerContractList) {
                // 循环处理押金结转
                depositCarryDown(orderId, renewalOwnerContract);
            }
        }
    }


    @Override
    public void handleRenewalOrder(Long contractId){
        // 判断业主根合同首期账单是否支付完成
        ContractHouseOwnerDO houseOwner = contractHouseOwnerService.getHouseOwner(contractId);
        Long rootId = null;
        if (Objects.isNull(houseOwner)){
            throw exception(HOUSE_OWNER_NOT_EXISTS);
        }
        if (Objects.nonNull(houseOwner.getRootId())){
            rootId = houseOwner.getRootId();
        }else {
            rootId = contractId;
        }
        RentOrderDO ownerFirstOrder = getOwnerFirstOrder(rootId);
        if (Objects.isNull(ownerFirstOrder) || !checkOwnerOrderDepositPayStatus(ownerFirstOrder)){
            return;
        }
        // 查询所有续租合同
        List<ContractHouseOwnerDO> renewalOwnerContractList = contractHouseOwnerService.getRenewalOwnerContractByContractId(rootId);
        if (CollectionUtils.isNotEmpty(renewalOwnerContractList)){
            for (ContractHouseOwnerDO renewalOwnerContract : renewalOwnerContractList) {
                depositCarryDown(ownerFirstOrder.getId(), renewalOwnerContract);
            }
        }
    }

    /**
     * 续租合同押金结转
     */
    private Long depositCarryDown(Long orderId, ContractHouseOwnerDO renewalOwnerContract) {
        // 修改续租合同首期账单及押金账单明细
        // 查询本账单押金账单明细
        List<OrderFeesDO> orderFeesList = getDepositOrderFees(orderId);
        if (CollectionUtils.isEmpty(orderFeesList)){
            return null;
        }
        // 付款账单的押金账单明细
        OrderFeesDO depositOrderFeesDO = orderFeesList.get(ZERO);
        // 续租合同首期账单
        RentOrderDO renewalFirstRentOrder = getOwnerFirstOrder(renewalOwnerContract.getId());
        if (Objects.isNull(renewalFirstRentOrder)){
            return null;
        }
        // 更新续租合同首期账单
        LambdaUpdateWrapper<RentOrderDO> renewalRentOrderUpdateWrapper = new LambdaUpdateWrapper<>();
        renewalRentOrderUpdateWrapper.eq(RentOrderDO::getId, renewalFirstRentOrder.getId());
        renewalRentOrderUpdateWrapper.set(RentOrderDO::getDepositAmount, depositOrderFeesDO.getAmount());
        renewalRentOrderUpdateWrapper.set(RentOrderDO::getRentDeposit, renewalFirstRentOrder.getRentDeposit().add(depositOrderFeesDO.getAmount()));
        renewalRentOrderUpdateWrapper.set(RentOrderDO::getPaidRentUtilities, renewalFirstRentOrder.getPaidRentUtilities().add(depositOrderFeesDO.getAmount()));
        //        renewalRentOrderUpdateWrapper.set(RentOrderDO::getTotalAmount, renewalFirstRentOrder.getTotalAmount().add(depositOrderFeesDO.getAmount()));
        renewalRentOrderUpdateWrapper.set(RentOrderDO::getTotalAmount,
                renewalFirstRentOrder.getRentAmount().add(renewalFirstRentOrder.getDepositAmount()).subtract(renewalFirstRentOrder.getDiscountAmount()));
        if (OrderPayStatusEnum.UNPAID.getCode().equals(renewalFirstRentOrder.getPayStatus())){
            renewalRentOrderUpdateWrapper.set(RentOrderDO::getPayStatus, OrderPayStatusEnum.PART.getCode());
        }
        rentOrderMapper.update(null, renewalRentOrderUpdateWrapper);
        // 续租合同首期账单押金账单明细
        LambdaQueryWrapper<OrderFeesDO> renewalDepositQueryWrapper = new LambdaQueryWrapper<>();
        renewalDepositQueryWrapper.eq(OrderFeesDO::getOrderId, renewalFirstRentOrder.getId());
        renewalDepositQueryWrapper.eq(OrderFeesDO::getFeeSort, OrderFeeSortTypeEnum.DEPOSIT.getCode());
        renewalDepositQueryWrapper.eq(OrderFeesDO::getFeeId, ApiConstants.DEPOSIT_FEE_ID);
        List<OrderFeesDO> renewalDepositFeesList = orderFeesMapper.selectList(renewalDepositQueryWrapper);
        if (CollectionUtils.isNotEmpty(renewalDepositFeesList)){
            // 续租合同首期账单押金账单明细
            OrderFeesDO renewalDepositFees = renewalDepositFeesList.get(ZERO);
            // 更新续租合同首期账单押金账单明细
            LambdaUpdateWrapper<OrderFeesDO> renewalDepositUpdateWrapper = new LambdaUpdateWrapper<>();
            renewalDepositUpdateWrapper.eq(OrderFeesDO::getId, renewalDepositFees.getId());
            renewalDepositUpdateWrapper.set(OrderFeesDO::getPayStatus, OrderPayStatusEnum.PAID.getCode());
            renewalDepositUpdateWrapper.set(OrderFeesDO::getAmount, depositOrderFeesDO.getAmount());
            renewalDepositUpdateWrapper.set(OrderFeesDO::getPaidAmount, depositOrderFeesDO.getAmount());
            orderFeesMapper.update(null, renewalDepositUpdateWrapper);
        }
        return renewalFirstRentOrder.getId();
    }


    @Override
    @Transactional
    public void payRent(BankTransferReqDTO req) {
        String orderNo = req.getBizNo();
        if (StringUtils.isBlank(orderNo)){
            throw exception(CONTRACT_RENTORDER_NOT_EXISTS);
        }
        RentOrderDO rentOrderDO = rentOrderMapper.selectOne(RentOrderDO::getOrderNo, orderNo);
        if (Objects.isNull(rentOrderDO)){
            throw exception(CONTRACT_RENTORDER_NOT_EXISTS);
        }
        if (OrderPayStatusEnum.PAID.getCode().equals(rentOrderDO.getPayStatus())){
            throw exception(ROOM_ORDER_ALREADY_PAID);
        }
        ContractHouseOwnerDO houseOwner = contractHouseOwnerService.getHouseOwner(rentOrderDO.getBusinessId());
        if (Objects.isNull(houseOwner)){
            throw exception(HOUSE_OWNER_NOT_EXISTS);
        }
        List<String> ownerStatusList = Arrays.asList(ContractOwnerStatusEnum.ACTIVE.getCode(),ContractOwnerStatusEnum.NORMAL_END.getCode());
        if (OrderTypeEnum.OWNER.equals(rentOrderDO.getOrderType()) &&
                (!ownerStatusList.contains(houseOwner.getContractStatus())
                || ContractNodeEnum.RENTING_OUT.getCode().equals(houseOwner.getContractNode()))){
            throw exception(OWNER_ORDER_STATUS_UNABLE_PAY);
        }
        // 已收账单总额
        BigDecimal paidRentUtilities = Objects.nonNull(rentOrderDO.getPaidRentUtilities())?rentOrderDO.getPaidRentUtilities():BigDecimal.ZERO;
        paidRentUtilities = rentOrderDO.getTotalAmount().subtract(paidRentUtilities);
        String payStatus = OrderPayStatusEnum.UNPAID.getCode();
        int compare = paidRentUtilities.compareTo(rentOrderDO.getTotalAmount());
        if (compare >= 0){
            payStatus = OrderPayStatusEnum.PAID.getCode();
        }
        if (BigDecimal.ZERO.compareTo(paidRentUtilities) > 0 && compare < 0) {
            payStatus = OrderPayStatusEnum.PART.getCode();
        }
        // 更新业主账单状态为已支付
        LambdaUpdateWrapper<RentOrderDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(RentOrderDO::getOrderNo, orderNo);
        updateWrapper.set(RentOrderDO::getPayStatus, payStatus);
        updateWrapper.set(RentOrderDO::getPaidRentUtilities, paidRentUtilities);
        rentOrderMapper.update(null, updateWrapper);
        // 更新业主账单明细
        orderFeesService.updateOrderFeePaid(rentOrderDO.getId(), payStatus);
        // 付款完成处理首期账单押金账单明细问题
        ownerOrderPaidHandleRenewalOrders(rentOrderDO.getId());

        req.setPayeeMobile(houseOwner.getPhone());
        req.setApartmentId(rentOrderDO.getApartmentId());
        req.setApartmentName(rentOrderDO.getApartmentName());
        req.setPayAmount(req.getPayAmount().abs());
        req.setContractNo(houseOwner.getContractNo());
        // 调用支付服务银企直连付款
        financeApi.bankTransfer(req);
    }


    @Override
    public Boolean checkOwnerOrderPaid(Long contractId, Integer contractType) {
        if (Objects.isNull(contractType)){
            return false;
        }
        LambdaQueryWrapper<RentOrderDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RentOrderDO::getBusinessId, contractId);
        queryWrapper.eq(RentOrderDO::getOrderType, OrderTypeEnum.OWNER.getCode());
        List<RentOrderDO> rentOrderDOList = rentOrderMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(rentOrderDOList)){
            return false;
        }
        Boolean result = false;
        List<RentOrderDO> firstRentOrderList = new ArrayList<>();
        if (ONE.intValue() == contractType){
            // 续租合同
            // 筛选出首期账单
            firstRentOrderList = rentOrderDOList.stream().filter(r -> (ONE.intValue() == r.getNum())).collect(Collectors.toList());
            // 除首期的账单列表
            if (CollectionUtils.isNotEmpty(rentOrderDOList)){
                rentOrderDOList.remove(firstRentOrderList);
            }
        }
        // 遍历业主账单有支付的账单返回
        for (RentOrderDO rentOrderDO : rentOrderDOList) {
            if (!OrderPayStatusEnum.UNPAID.getCode().equals(rentOrderDO.getPayStatus())){
                return true;
            }
        }
        // 续租合同账单首期账单单独判断
        if (CollectionUtils.isNotEmpty(firstRentOrderList)){
            for (RentOrderDO rentOrderDO : firstRentOrderList) {
                LambdaQueryWrapper<OrderFeesDO> renewalDepositQueryWrapper = new LambdaQueryWrapper<>();
                renewalDepositQueryWrapper.eq(OrderFeesDO::getOrderId, rentOrderDO.getId());
                List<OrderFeesDO> renewalFeesList = orderFeesMapper.selectList(renewalDepositQueryWrapper);
                if (CollectionUtils.isNotEmpty(renewalFeesList)){
                    for (OrderFeesDO orderFeesDO : renewalFeesList) {
                        // 非押金账单明细支付过 返回true
                        if ((!OrderFeeSortTypeEnum.DEPOSIT.getCode().equals(orderFeesDO.getFeeSort())
                                || ApiConstants.DEPOSIT_FEE_ID.intValue() == orderFeesDO.getFeeId())
                                && !OrderPayStatusEnum.UNPAID.getCode().equals(orderFeesDO.getPayStatus())){
                            return true;
                        }
                    }
                }
            }
        }
        return result;
    }


    @Override
    public List<RentOrderDO> getListByParam(RentOrderQueryDTO param) {
        if (Objects.isNull(param)){
            return null;
        }
        LambdaQueryWrapper<RentOrderDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Objects.nonNull(param.getBusinessId()),RentOrderDO::getBusinessId, param.getBusinessId());
        queryWrapper.eq(StringUtils.isNotBlank(param.getOrderType()),RentOrderDO::getOrderType, param.getOrderType());
        queryWrapper.eq(StringUtils.isNotBlank(param.getPayStatus()), RentOrderDO::getPayStatus,param.getPayStatus());
        queryWrapper.in(CollectionUtils.isNotEmpty(param.getPayStatusList()), RentOrderDO::getPayStatus,param.getPayStatusList());
        return rentOrderMapper.selectList(queryWrapper);
    }


    @Override
    public PageResult<OwnerOrderPageRespVO> getOwnerOrderHomePage(HomeQueryVO queryDTO) {
        Page<OwnerOrderPageRespVO> page = new Page<>(queryDTO.getPageNo(),queryDTO.getPageSize());
        IPage<OwnerOrderPageRespVO> ownerOrderPage = rentOrderMapper.getOwnerOrderHomePage(page, queryDTO);
        if (Objects.isNull(ownerOrderPage)){
            return null;
        }
        List<OwnerOrderPageRespVO> records = ownerOrderPage.getRecords();
        for (OwnerOrderPageRespVO record : records) {
            // 状态处理
            long differDays = queryDTO.getStartDate().toEpochDay() - record.getDeadlinePayTime().toEpochDay();
            if (0L == differDays){
                record.setStatusStr("应处理");
            }else {
                record.setStatusStr(String.format("已逾期%s天", differDays));
            }
        }
        return new PageResult<>(records,  ownerOrderPage.getTotal());
    }

    @Override
    public void suspend(OwnerOrderSuspendReqVO reqVO) {
        RentOrderDO rentOrderDO = rentOrderMapper.selectById(reqVO.getOrderId());
        if (rentOrderDO == null) {
            return;
        }
        //审核中无法操作
        if (OrderApprovedStatusEnum.IN_REVIEW.getCode().equals(rentOrderDO.getApprovedStatus())) {
            throw exception(OWNER_ORDER_IN_REVIEW_ERROR);
        }
        //应付款单中存在无法进行操作
        int i = rentOrderMapper.countContractOwnerBankTransfer(rentOrderDO.getId());
        if (i > 0) {
            throw exception(OWNER_ORDER_PAYMENT_ERROR);
        }
        rentOrderMapper.updateById(RentOrderDO.builder()
                .id(reqVO.getOrderId())
                .suspend(reqVO.getSuspend())
                .suspendAt(reqVO.getSuspend() ? LocalDateTime.now() : null)
                .build());
    }

    @Override
    public void createRenterOrderTransfer() {
        try {
            rentOrderMapper.createRenterOrderTransfer();
        } catch (UnsupportedOperationException e) {
            // 首次执行会报错
            log.error("委托付款首次执行错误");
            rentOrderMapper.createRenterOrderTransfer();
        }
    }

    /**
     * 批量发起委托账单审批
     */
    @Override
    public void batchApprovalRenterOrder() {
        IPage<OwnerOrderTransferDO> page = new Page<>(1, 200);
        recursiveProcessing(page);
    }

    /**
     * 审批回调
     *
     * @param event
     */
    @Override
    public void approvalResult(BpmProcessInstanceResultEvent event) {
        RentOrderDO rentOrderDO = rentOrderMapper.selectById(event.getBusinessKey());
        if (ObjectUtil.isEmpty(rentOrderDO)) {
            log.error("订单id为【{}】不存在", event.getBusinessKey());
            return;
        }
        if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(event.getResult())) {
            //修改为生效
            rentOrderMapper.updateById(
                    RentOrderDO.builder().id(rentOrderDO.getId())
                            .approvedStatus(OrderApprovedStatusEnum.HAVE_TAKEN_EFFECT.getCode()).build());
            rentOrderMapper.createRenterOrderTransferByOrderIds(CollectionUtil.newArrayList(Long.parseLong(event.getBusinessKey())));

        } else {
            //拒绝驳回
            rentOrderMapper.updateById(
                    RentOrderDO.builder().id(rentOrderDO.getId())
                            .approvedStatus(OrderApprovedStatusEnum.REJECT.getCode()).build());
        }
    }

    /**
     * 获取业主账单打款详情
     *
     * @param id
     * @return {@link OwnerOrderApprovalDetailVO}
     */
    @Override
    public OwnerOrderApprovalDetailVO ownerOrderApprovalDetailById(Long id) {
        RentOrderDO rentOrderDO = rentOrderMapper.selectById(id);
        OwnerOrderApprovalDetailVO vo = new OwnerOrderApprovalDetailVO();
        Optional.ofNullable(rentOrderDO).ifPresent(f -> {
            RentOrderConvert.INSTANCE.convertApprovalDetail2(f, vo);
            CommonResult<Map<String, Object>> processVariablesMap =
                    bpmProcessInstanceApi.getProcessVariablesMap(rentOrderDO.getProcessInstance());
            //为了兼容历史数据
            //流程函数存在 取流程中的
            if (processVariablesMap.isSuccess() && ObjectUtil.isNotNull(processVariablesMap.getData())) {
                Optional.ofNullable(processVariablesMap.getData().get("pay_amount")).ifPresent(
                        a -> {
                            vo.setPayAmount(new BigDecimal(a.toString()));
                        }
                );
            }
            if (ObjectUtil.isNull(vo.getPayAmount())) {
                //流程中未支付  取处理的
                //如果已付
                if (OrderPayStatusEnum.PAID.getCode().equals(f.getPayStatus())) {
                    vo.setPayAmount(f.getActualPaymentAmount());
                } else {
                    vo.setPayAmount(f.getTotalAmount().subtract(f.getPaidRentUtilities()));
                }
            }
            Optional.ofNullable(contractHouseOwnerService.getHouseOwner(rentOrderDO.getBusinessId())).ifPresent(
                    b -> {
                        RentOrderConvert.INSTANCE.convertApprovalDetail(b, vo);
                        //合同创建人
                        String creator = b.getCreator();
                        Optional.ofNullable(creator).ifPresent(c -> {
                            CommonResult<AdminUserRespDTO> user = adminUserApi.getUser(Long.parseLong(creator));
                            if (user.isSuccess() && ObjectUtil.isNotEmpty(user.getData())) {
                                //写入合同创建人
                                vo.setCreatorName(user.getData().getNickname());
                            }
                        });
                    }
            );

        });
        return vo;
    }

    /**
     * 业主账单id
     *
     * @param id
     */
    @Override
    public void ownerOrderCreateApproval(Long id) {
        RentOrderDO rentOrderDO = rentOrderMapper.selectById(id);
        //账单不存在
        if (ObjectUtil.isEmpty(rentOrderDO)) {
            throw exception(OWNER_ORDER_ABSENT);
        }
        //非驳回无法发起
        if (!OrderApprovedStatusEnum.REJECT.getCode().equals(rentOrderDO.getApprovedStatus())) {
            throw exception(OWNER_ORDER_ERROR);
        }
        //循环发起审批
        String mark = contractApprovalService.getByRoomIdAndMark(rentOrderDO.getApartmentId(),
                ApproveTypeEnum.PAYMENT_BY_THE_OWNER.getMsg());
        if (StringUtils.isNotBlank(mark)) {
            //发起审批
            String processInstance = createProcessInstance(mark, rentOrderDO, getLoginUser().getId(),
                    getLoginUser().getNickname());
            rentOrderMapper.updateById(
                    RentOrderDO.builder().id(rentOrderDO.getId()).processInstance(processInstance)
                            .approvedStatus(OrderApprovedStatusEnum.IN_REVIEW.getCode()).build());
        } else {
            rentOrderMapper.createRenterOrderTransferByOrderIds(CollectionUtil.newArrayList(rentOrderDO.getId()));
        }
    }

    /**
     * 递归处理
     */
    private void recursiveProcessing(IPage<OwnerOrderTransferDO> page) {
        IPage<RentOrderDO> pendPage = rentOrderMapper.selectOwnerPendingApprovalPage(page);
        List<RentOrderDO> records = pendPage.getRecords();
        if (CollectionUtil.isNotEmpty(records)) {
            Map<Long, List<RentOrderDO>> collect =
                    records.stream().collect(Collectors.groupingBy(RentOrderDO::getApartmentId));
            collect.keySet().forEach(f -> {
                //没有门店id
                if (ObjectUtil.isEmpty(f))
                    return;
                //循环发起审批
                String mark = contractApprovalService.getByRoomIdAndMark(f,
                        ApproveTypeEnum.PAYMENT_BY_THE_OWNER.getMsg());
                //如果需要审批
                if (StringUtils.isNotBlank(mark)) {
                    //循环发起审批
                    collect.get(f).forEach(b -> {
                        String userName = "";
                        Long userId = 0l;
                        if (StringUtils.isNotBlank(b.getCreator())) {
                            userId = Long.parseLong(b.getCreator());
                            CommonResult<AdminUserRespDTO> user = adminUserApi.getUser(userId);
                            if (user.isSuccess() && ObjectUtil.isNotEmpty(user.getData())) {
                                userName = user.getData().getNickname();
                            }

                        }
                        //发起审批
                        String processInstance = createProcessInstance(mark, b, userId, userName);
                        rentOrderMapper.updateById(
                                RentOrderDO.builder().id(b.getId()).processInstance(processInstance)
                                        .approvedStatus(OrderApprovedStatusEnum.IN_REVIEW.getCode()).build()
                        );
                    });
                    return;
                }

                try {
                    rentOrderMapper.createRenterOrderTransferByOrderIds(collect.get(f).stream().map(RentOrderDO::getId).collect(Collectors.toList()));
                } catch (Exception e) {
                    // 首次执行会报错
                    log.error("委托付款首次执行错误");
                }

            });

            if (records.size() == page.getSize()) {
                recursiveProcessing(page.setCurrent(page.getCurrent() + 1));
            }
        }
    }

    private String createProcessInstance(String mark, RentOrderDO orderDO, Long userId, String userName) {
        // 工作流参数
        BpmProcessInstanceCreateReqDTO bpmProcessInstanceCreateReqDTO = new BpmProcessInstanceCreateReqDTO();
        bpmProcessInstanceCreateReqDTO.setProcessDefinitionKey(mark);
        bpmProcessInstanceCreateReqDTO.setBusinessType(BpmBusinessTypeEnum.PAYMENT_BY_THE_OWNER.name());
        bpmProcessInstanceCreateReqDTO.setBusinessKey(String.valueOf(orderDO.getId()));
        bpmProcessInstanceCreateReqDTO.setTenantId(orderDO.getTenantId());
        bpmProcessInstanceCreateReqDTO.setServiceName(applicationName);
        log.info("processInstance userId {}, request : {}", userId,
                JsonUtils.toJsonString(bpmProcessInstanceCreateReqDTO));
        HashMap<String, Object> map = MapUtil.of("createName", userName);
        //实付金额
        map.put("pay_amount", orderDO.getTotalAmount().subtract(orderDO.getPaidRentUtilities()));

        //写入临时的
        bpmProcessInstanceCreateReqDTO.setVariables(map);

        // 查询业主合同信息
        ContractHouseOwnerRespVO contractHouseOwner =
                contractHouseOwnerService.getHouseOwnerWithRefRoom(orderDO.getBusinessId());
        ContractOwnerRoomRefVO contractRefRoom = contractHouseOwner.getRefRoom();
        BpmProcessInstanceCreateReqDTO.ExtendDto extendDto = new BpmProcessInstanceCreateReqDTO.ExtendDto();
        extendDto.setRoomId(Objects.nonNull(contractRefRoom.getRoomId()) ? contractRefRoom.getRoomId().toString() : "");
        extendDto.setContractId(null);
        extendDto.setContractNo(contractHouseOwner.getContractNo());
        extendDto.setOwnerContractId(contractHouseOwner.getId());
        extendDto.setRoomName(contractRefRoom.getRoomName());
        extendDto.setApartmentId(contractRefRoom.getApartmentId());
        extendDto.setApartmentName(null);
        extendDto.setCustomName(contractHouseOwner.getOwnerName());
        extendDto.setCustomPhone(contractHouseOwner.getPhone());
        bpmProcessInstanceCreateReqDTO.setExtendDto(extendDto);
        CommonResult<String> processInstance =
                bpmProcessInstanceApi.createProcessInstance(userId,
                        bpmProcessInstanceCreateReqDTO);
        log.info("processInstance:{}", JsonUtils.toJsonString(processInstance));
        return processInstance.getCheckedData();

    }

    @Override
    public PageResult<OwnerOrderTransferDO> getTransferPage(OwnerOrderTransferPageReqVO reqVO) {
        IPage<OwnerOrderTransferDO> mpPage = MyBatisUtils.buildPage(reqVO);
        rentOrderMapper.selectOwnerTransferPage(reqVO, mpPage);
        AtomicInteger index = new AtomicInteger((reqVO.getPageNo() - 1) * reqVO.getPageSize() + 1);
        if (CollectionUtil.isNotEmpty(mpPage.getRecords())) {
            mpPage.getRecords().forEach(f -> {
                f.setSerialNumber(index.getAndIncrement());
            });
        }
        return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
    }

    @Override
    @Transactional
    public void transfer(OwnerOrderTransferReqVO reqVO, String operator) {
        List<OwnerOrderTransferDO> transferDOs = rentOrderMapper.selectOwnerTransfer(reqVO.getId());
        if (CollectionUtils.isEmpty(transferDOs)) {
            return;
        }
        List<BankTransferReqDTO> l = transferDOs.stream().map(transferDO -> {
            BankTransferReqDTO reqDTO = new BankTransferReqDTO();
            reqDTO.setBizDate(LocalDate.now());
            reqDTO.setNumber(transferDO.getNumber());
            reqDTO.setApartmentName(transferDO.getApartmentName());
            reqDTO.setApartmentId(transferDO.getApartmentId());
            reqDTO.setRoomId(transferDO.getRoomId());
            reqDTO.setRoomName(transferDO.getRoomName());
            reqDTO.setOperator(operator);
            reqDTO.setPayeeName(transferDO.getPayeeName());
            reqDTO.setPayeeType("业主");
            reqDTO.setPayeeMobile(transferDO.getOwnerPhone());
            reqDTO.setPayAmount(transferDO.getPayAmount());
            reqDTO.setPayeeBank(transferDO.getPayeeBank());
            reqDTO.setPayeeBankBranch(transferDO.getPayeeBankBranch());
            reqDTO.setPayeeBankCode(transferDO.getPayeeBankCode());
            reqDTO.setPayeeBankProvince(transferDO.getPayeeBankProvince());
            reqDTO.setPayeeBankCity(transferDO.getPayeeBankCity());
            reqDTO.setContractNo(transferDO.getContractNo());
            reqDTO.setPayeeBankAccount(transferDO.getPayeeBankAccount());
            reqDTO.setBizNo(transferDO.getOrderNo());
            reqDTO.setBizType(SourceBizTypeEnum.OWNER_ORDER.name());
            reqDTO.setReason("委托业务付款");
            return reqDTO;
        }).collect(Collectors.toList());
        CommonResult<Void> result = financeApi.bankTransferBatch(l);
        result.getCheckedData();
        rentOrderMapper.confirmOwnerTransfer(transferDOs.stream().map(OwnerOrderTransferDO::getId).collect(Collectors.toSet()),
                FinanceCommonStatusEnum.WAITING.name(), operator);
    }

    @Override
    public List<OwnerOrderTransferDO> getTransferList(String[] ids) {
        return rentOrderMapper.selectOwnerTransfer(ids);
    }

    @Override
    public OwnerOrderTransferDO getTransferDetail(Long id) {
        List<OwnerOrderTransferDO> l = rentOrderMapper.selectOwnerTransfer(new Object[]{id});
        return CollectionUtils.isEmpty(l) ? null : l.get(0);
    }

    @Override
    public OwnerOrderTransferPageRespVO getTransferSummary(OwnerOrderTransferPageReqVO reqVO) {
        List<Map<String, Object>> l = rentOrderMapper.selectOwnerTransferConfirmSummary(reqVO);
        BigDecimal totalPaid = BigDecimal.ZERO;
        BigDecimal totalFailure = BigDecimal.ZERO;
        BigDecimal totalWaiting = BigDecimal.ZERO;
        BigDecimal totalSubmit = BigDecimal.ZERO;
        int totalPaidCount = 0;
        int totalFailureCount = 0;
        int totalWaitingCount = 0;
        int totalSubmitCount = 0;

        for (Map<String, Object> m : l) {
            Object status = m.get("status");
            Object payAmount = m.get("payAmount");
            Object count = m.get("cnt");
            if (OwnerTransferStatusEnum.SUCCESS.name().equals(status)) {
                totalPaid = new BigDecimal(payAmount.toString());
                totalPaidCount = Integer.parseInt(count.toString());
            } else if (OwnerTransferStatusEnum.WAITING.name().equals(status)) {
                totalWaiting = new BigDecimal(payAmount.toString());
                totalWaitingCount = Integer.parseInt(count.toString());
            } else if (OwnerTransferStatusEnum.FAILURE.name().equals(status)) {
                totalFailure = new BigDecimal(payAmount.toString());
                totalFailureCount = Integer.parseInt(count.toString());
            } else if (OwnerTransferStatusEnum.SUBMIT.name().equals(status)) {
                totalSubmit = new BigDecimal(payAmount.toString());
                totalSubmitCount = Integer.parseInt(count.toString());
            }
        }
        return OwnerOrderTransferPageRespVO.builder().totalPaid(totalPaid)
                .totalPaidCount(totalPaidCount)
                .totalFailure(totalFailure)
                .totalFailureCount(totalFailureCount)
                .totalWaiting(totalWaiting)
                .totalWaitingCount(totalWaitingCount)
                .totalSubmitCount(totalSubmitCount)
                .totalSubmit(totalSubmit)
                .build();
    }

    @Override
    public void transferCallback(OwnerOrderTransferCallbackReqVO reqVO) {
        if (StringUtils.isNotBlank(reqVO.getOrderNo())) {
            rentOrderMapper.updateOwnerOrderTransfer(reqVO);
            if (FinanceCommonStatusEnum.SUCCESS.name().equals(reqVO.getStatus())){
                // 修改业主合同账单状态
                rentOrderMapper.updateOwnerOrder(reqVO);
            }
        }
    }
}
